home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 98 / Skunkware 98.iso / osr5 / sco / scripts / admin / mmdf / smtpcull < prev   
Encoding:
Korn shell script  |  1997-08-26  |  8.8 KB  |  190 lines

  1. #!/bin/ksh
  2. # ^^^ replace this with #!/bin/sh if you do not have /bin/ksh
  3. # @(#) smtpcull.sh 1.3 97/07/22
  4. # 96/07/18 john h. dubois iii (john@armory.com)
  5. # 96/07/25 Portability: avoid fgrep -q and print.
  6. # 97/02/06 Also search for "parents" of domains/networks
  7. # 97/02/10 If resolver gives multiple names, search for all of them.
  8. # 97/05/02 Give a more verbose message to spamsites.
  9. # 97/07/22 1.3 Added hostname mapping
  10.  
  11. # The most recent version of this utility is always available at:
  12. # ftp://ftp.armory.com./pub/admin/mmdf/smtpcull
  13.  
  14. # This program is invoked as: smtpsrvr remotename localname channel-list
  15. # If resolver gives multiple names for an IP address, they will all be passwd
  16. # as arg 1 to smtpsrver, separated by whitespace.
  17.  
  18. blacklist=/usr/mmdf/table/blacklist
  19. hostmap=/usr/mmdf/table/hostmap
  20.  
  21. ###
  22. # This first code implements hostname mapping.  This allows the value
  23. # returned by a PTR lookup to be mapped to some other name.  This can be used
  24. # to e.g. deal with the problem of an uncooperative ISP who refuses to make
  25. # PTR records resolve correctly.  For example, if a PTR lookup on a host gives
  26. # a bogus name, it will be accepted by MMDF, but if handed off to a very picky
  27. # MTA (one that checks each hostname in the return path for validity) it may be
  28. # rejected. The hostname map is stored in the file /usr/mmdf/table/hostmap and
  29. # consists of one pair of hostnames on each line, separated from each other by
  30. # whitespace.
  31. # If the value returned by a PTR lookup (or any superdomain of it) appears on
  32. # the lefthand side of any line, its value will be replaced by whatever appears
  33. # on the righthand side.  This currently only works for PTR lookups that return
  34. # a single value.  Example line:
  35. # dynamic.foo.com realhost.domain.name
  36. # A PTR return of dynamic.foo.com or *.dynamic.foo.com will be replaced by
  37. # realhost.domain.name (realhost.domain.name will appear in the return address)
  38. ###
  39. if [ -f $hostmap -a -r $hostmap ]; then
  40.     mapped=`awk -v "host=$1" ' BEGIN { hlen = length(host); } $1 == host || \
  41.     ("." $1) == substr(host,hlen - length($1)) { print $2; }' $hostmap`
  42.     if [ -n "$mapped" ]; then
  43.     shift
  44.     set -- "$mapped" "$@"
  45.     fi
  46. fi
  47.  
  48. ### The rest of the code implements the blacklist
  49. if [ ! -f $blacklist -o ! -r $blacklist ]; then
  50.     /usr/bin/logger -i -tsmtpsrvr "Accepted (no blacklist): $1"
  51.     exec /usr/mmdf/chans/smtpsrvr.bin "$@"
  52. fi
  53.  
  54. # For each hostname/IP address passed, add the hostname/IP address and all
  55. # of its parent domains/supernets to the list of names to be searched for in
  56. # the blacklist.
  57. if [ "$RANDOM" != "$RANDOM" ]; then
  58.     # if in ksh, use builtins
  59.     for hostname in $1; do
  60.     if [ -z "$names" ]; then
  61.         names=$hostname
  62.     else
  63.         names="$names
  64. $hostname"
  65.     fi
  66.     pname=$hostname
  67.     while [[ "$pname" = *.*.* ]]; do
  68.         [[ "$hostname" = *[!0-9.]* ]] && pname=${pname#*.} ||
  69.         pname=${pname%.*}
  70.         names="$names
  71. $pname"
  72.     done
  73.     done
  74. else
  75.     names=`echo "$1" | awk '
  76. {
  77.     for (i = 1; i <= NF; i++) {
  78.     hostname = $i
  79.     print hostname
  80.     while (hostname ~ /\..*\./) {
  81.         if (hostname ~ /[^0-9.]/)
  82.         sub("^[^.]+.","",hostname)
  83.         else
  84.         sub(".[^.]+$","",hostname)
  85.         print hostname
  86.     }
  87.     }
  88. }'`
  89. fi
  90.  
  91. # If your fgrep does not understand '--' to end an option list, replace the
  92. # -- with /dev/null.
  93. if /usr/bin/fgrep -ix -- "$names" $blacklist >/dev/null 2>&1
  94. then
  95.     /usr/bin/logger -i -tsmtpsrvr "Rejected: $1"
  96.     /bin/sleep 3
  97.     # RFC821 allows multiline responses for all commands.
  98.     # All but the last must begin with "<reply-code>-".
  99.     echo \
  100. "550-We do not accept mail from sites that primarily originate spam.  If the
  101. 550-site that your mail passes through has been incorrectly identified as a
  102. 550-source of unsolicited commercial email, please send mail to this effect to
  103. 550-postmaster@`/usr/bin/hostname` to have the situation rectified.  You will
  104. 550-have to send mail through an alternate host in order for it to get through.
  105. 550 We apologize for any inconvenience."
  106.     /bin/sleep 3
  107.     exit 0
  108. else
  109.     /usr/bin/logger -i -tsmtpsrvr "Accepted: $1"
  110.     exec /usr/mmdf/chans/smtpsrvr.bin "$@"
  111. fi
  112.  
  113. # Instructions and description (keep these at the end so that sh does not have
  114. # to read the comments every time it runs this script):
  115. # In /usr/mmdf/chans, move smtpsrvr to smtpsrvr.bin
  116. # Save this file there as smtpsrvr, and give it mode 755.
  117. # Create the file /usr/mmdf/table/blacklist, and in it list each domain name
  118. # that mail should not be accepted from, one per line, with no whitespace
  119. # before or after the name.  Case is not significant, everything else is.
  120. # For each domain name, connections from a host with that name or any subdomain
  121. # of it will be rejected.  E.g. if "spammers.com" is listed, connections from
  122. # spammers.com, lame.spammers.com, extremely.lame.spammers.com, etc. will be
  123. # rejected.  If an IP address is looked up (see below), connections from a
  124. # listed network or any subnet of it are rejected; i.e. components of the IP
  125. # address are removed from the right when searching for matches to "parent"
  126. # networks, rather than the left as is done with hostnames.  So, if 1.2.3 is
  127. # listed, connections from 1.2.3.* will be rejected.
  128. # Names & IP addresses must have at least two components (i.e., must contain
  129. # at least one '.').  
  130. # The file does not need any special permissions; this program will be run as
  131. # root.
  132. # All connections will be logged by logger at default priority in syslog,
  133. # as either "Accepted" or "Rejected", followed by the hostname that was used
  134. # to make the determination.  If you don't know the real hostname that a
  135. # message came from so that it can be blacklisted, check syslog or look at the
  136. # Received: lines in the message header (in some MUAs the Received: lines may
  137. # be suppressed by default, so you may need to specifically ask to see them).
  138. # Be aware that the administrator of the PTR records for a network can make
  139. # connections appear to come from any host.  Currently, this program uses
  140. # the hostname that smtpd gets by doing an PTR lookup on the IP address that
  141. # a connection comes from.  It does NOT use the "HELO" name; that part of
  142. # the SMTP transaction has not happened at the time that this program runs
  143. # (in fact, there has been no SMTP exchange at all at the time this program
  144. # runs).  If the PTR lookup fails for any reason, smtpd gives the IP address
  145. # to smtpsrvr, so you may find that you need to put some IP addresses in the
  146. # blacklist file as well.  When an IP address is looked up, both 
  147. # Enhancements to this program would be to allow general blacklisting by IP
  148. # address, and doing A lookups on the result of PTR lookups to confirm them.
  149. # The failure message returned to the remote SMTP daemon for rejected
  150. # connections is given on the 'echo' line above.  You may with to change it to
  151. # suit the purpose you use this program for because the rejection line will
  152. # typically be included in the return mail the remote SMTP daemon sends to the
  153. # return address of the rejected message.  Be sure to keep the "550" at the
  154. # beginning of each line; this code tells the remote SMTP daemon that a fatal
  155. # error has occured and it should not try to keep sending the message (note
  156. # that some SMTP daemons retry anyway).
  157. # Here are two examples of message headers:
  158. # From ns.pdev.armory.com!foo.armory.com!ftp.interline.net!mail.interline.net!bargain Wed Jul 24 22:20:27 1996
  159. # Received: from ns.pdev.armory.com by father.pdev.armory.com id aa03887;
  160. #           24 Jul 96 22:20 PDT
  161. # Received: from foo.armory.com by grandpa.pdev.armory.com id aa19416;
  162. #           24 Jul 96 22:21 PDT
  163. # Received: from ftp.interline.net by foo.armory.COM id aa27305; 24 Jul 96 22:13 PDT
  164. # Received: from ppp6.interline.net by primary.interline.net (NTMail 3.02.07)
  165. # Comments: Authenticated sender is <Bargain@mail.interline.net>
  166. # From: Bargain@mail.interline.net
  167. # The above example shows a message from a user claiming to have a mailbox on
  168. # mail.interline.net, with the first Received: line showing it came from 
  169. # ppp6.interline.net, being passed to a host that identifies itself as
  170. # primary.interline.net, and next being passed to foo.armory.COM.  However,
  171. # note that foo.armory.COM believes the message came from ftp.interline.net.
  172. # That name comes from the same source that smtpcull sees, namely the PTR
  173. # lookup done by smtpd.  Therefore, the name to put in the blacklist file on
  174. # foo.armory.COM would be "ftp.interline.net".
  175. # From moneyworld.com!chag Wed Jul 24 23:24:40 1996
  176. # Received: from [208.129.19.69] by deepthought.armory.com id aa02419;
  177. #           24 Jul 96 23:24 PDT
  178. # To: Bela Lubkin  <filbo@armory.com>
  179. # From: chag@moneyworld.com
  180. # In this example, the user claims to have a mailbox on moneyworld.com.  It
  181. # is passed immediately to deepthought.armory.com.  There is no PTR record
  182. # for the IP address that deepthought received it from, so smtpd on
  183. # deepthought.armory.com gives its IP address instead.  The name to put in
  184. # the blacklist file on deepthought.armory.com would be "208.129.19.69".
  185.